﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Proggy.Data.Abstract;
using Proggy.Data.Entities;
using Proggy.Data.Concrete;
using System.Data.Entity;

namespace Proggy.Data.Concrete
{
    /// <summary>
    /// Concrete Node repository
    /// </summary>
    public class NodeRepository : INodeRepository
    {
        /// <summary>
        /// Constructor with injection
        /// </summary>
        /// <param name="dc"></param>
        public NodeRepository(IProggyDataContext dc)
        {
            this._dc = dc;
        }

        /// <summary>
        /// private data context
        /// </summary>
        private IProggyDataContext _dc;

        /// <summary>
        /// Returns node entity from node id
        /// </summary>
        /// <param name="nodeId"></param>
        /// <returns></returns>
        public PublishableNode GetPublishableNodeFromNodeId(int nodeId)
        {
            //
            return this._dc.PublishableNodes.Find(nodeId);
        }

        /// <summary>
        /// Create new node
        /// </summary>
        /// <param name="model"></param>
        /// <param name="errorMsg"></param>
        /// <param name="newPublishableNodeId"></param>
        /// <returns></returns>
        public bool CreateNewNode(PublishableNode model, int? parentNodeId, ref string errorMsg, ref int newPublishableNodeId)
        {
            try
            {
                // start parent
                PublishableNode parent = null;

                // 
                if (parentNodeId != null)
                {
                    parent = this._dc.PublishableNodes.Find((int)parentNodeId);
                }

                // do basic checks
                var model_ = model;
                model_.ParentNode = parent;
                if (!this.NameIsOk(model_, NodeType.Draft, ref errorMsg)) { return false; }
                if (!this.UrlIsOk(model_, NodeType.Draft, ref errorMsg)) { return false; }
                if (!this.UniqueAliasIsUnique(model_, NodeType.Draft, ref errorMsg)) { return false; }

                // check parent
                if (parent != null)
                {
                    // set parent as draft
                    model.ParentNode = parent;

                    // get siblings
                    var siblings = this.GetSiblingsForNode(model_).ToList(); //realParentNode.ChildNodes.Where(x => x.PublishableNodeId != id).ToList();

                    // set order / level
                    model.OrderInParent = siblings.Count;
                    model.LevelInTree = parent.LevelInTree + 1;
                }
                else
                {
                    // is root so do specific sets
                    model.OrderInParent = 0;
                    model.LevelInTree = 0;
                }


                // set more stuff
                model.FirstCreated = DateTime.Now;
                model.LastUpdated = DateTime.Now;


                // create publishable
                var publishable = new PublishableNode
                {
                    ControllerNameSpace = model.ControllerNameSpace,
                    FirstCreated = model.FirstCreated,
                    FirstCreatedUsername = model.FirstCreatedUsername,
                    LastUpdatedUsername = model.LastUpdatedUsername,
                    FirstPublished = null,
                    LastUpdated = model.LastUpdated,
                    LevelInTree = model.LevelInTree,
                    Name = model.Name,
                    OrderInParent = model.OrderInParent,
                    Template = model.Template,
                    TypeAlias = model.TypeAlias,
                    TypeAssemblyName = model.TypeAssemblyName,
                    UrlPortion = model.UrlPortion.TrimEnd('-'),
                    ContentModelNameSpace = model.ContentModelNameSpace,
                    ParentNode = parent,
                    UniqueAlias = model.UniqueAlias
                };

                // save
                this._dc.PublishableNodes.Add(publishable);
                this._dc.SaveChanges(); // sets publishable id

                // relate
                publishable.DraftNode = this.CreateAndGetDraftForPublished(publishable);

                // save again
                this._dc.SaveChanges();

                // set new nodeid
                newPublishableNodeId = publishable.PublishableNodeId;

                // refresh
                //this.refreshDc();

                // ok!
                return true;

            }
            catch (Exception ex)
            {
                //
                errorMsg = "An unspecified error has occured whilst creating new content: " + ex.Message;
                return false;
            }
        }

        /// <summary>
        /// Creates and returns a new draft node for a publishable node (based on publishable node's properties)
        /// </summary>
        /// <param name="published"></param>
        /// <returns></returns>
        public DraftNode CreateAndGetDraftForPublished(PublishableNode published)
        {
            // get pusblished
            var published_ = this._dc.PublishableNodes.Single(x => x.PublishableNodeId == published.PublishableNodeId);

            // create draft
            var draft = new DraftNode
            {
                ContentModelNameSpace = published_.ContentModelNameSpace,
                ControllerNameSpace = published_.ControllerNameSpace,
                LastUpdated = published_.LastUpdated,
                FirstCreated = published_.FirstCreated,
                LastUpdatedUsername = published_.LastUpdatedUsername,
                FirstCreatedUsername = published_.FirstCreatedUsername,
                Name = published_.Name,
                SavedContentModelData = published_.SavedContentModelData,
                Template = published_.Template,
                TypeAlias = published_.TypeAlias,
                TypeAssemblyName = published_.TypeAssemblyName,
                UrlPortion = published_.UrlPortion,
                UniqueAlias = published_.UniqueAlias
            };

            // add to draft
            this._dc.DraftNodes.Add(draft);

            // set publishable
            published_.DraftNode = draft;

            // save            
            this._dc.SaveChanges();

            //
            return draft;
        }

        /// <summary>
        /// Returns root node or null
        /// </summary>
        /// <returns></returns>
        public PublishableNode GetRootNode()
        {
            //return this.PublishableNodes./*AsEnumerable().*/SingleOrDefault(x => x.IsRoot);
            return this._dc.PublishableNodes.SingleOrDefault(x => x.ParentNode == null);
        }

        /// <summary>
        /// Save draft
        /// </summary>
        /// <param name="publishableNodeId"></param>
        /// <param name="jsonData"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool SaveDraftNode(int publishableNodeId, string name, string urlSlug, string uniqueAlias, string template, string jsonData, string currentUsername, ref string errorMsg)
        {
            try
            {
                // refresh
                //this.refreshDc();

                // get node
                var publishable = this._dc.PublishableNodes
                    .Include("DraftNode")
                    .SingleOrDefault(x => x.PublishableNodeId == publishableNodeId);

                // check
                if (publishable == null)
                {
                    errorMsg = "Publishable node #" + publishableNodeId + " does not exist.";
                    return false;
                }

                // get draft
                var draft = publishable.DraftNode;

                // check
                if (draft == null)
                {
                    // try get explicitly                    
                    errorMsg = "Publishable node #" + publishableNodeId + " has no draft node. Data may have changed since you began editing.";
                    return false;
                }

                // set
                draft.SavedContentModelData = jsonData;
                draft.LastUpdated = DateTime.Now;
                draft.LastUpdatedUsername = currentUsername;
                draft.Name = name;
                draft.UrlPortion = urlSlug.TrimEnd('-');
                draft.UniqueAlias = uniqueAlias;
                draft.Template = template;

                if (!this.NameIsOk(draft, NodeType.Draft, ref errorMsg)) { return false; }
                if (!this.UrlIsOk(draft, NodeType.Draft, ref errorMsg)) { return false; }
                if (!this.UniqueAliasIsUnique(draft, NodeType.Draft, ref errorMsg)) { return false; }

                // save
                this._dc.SaveChanges();

                // refresh
                //this.refreshDc();

                // ok!!
                return true;
            }
            catch (Exception ex)
            {
                errorMsg = "An error has occured: " + ex.Message;
                return false;
            }
        }

        /// <summary>
        /// Publish draft to publishable and delete draft
        /// </summary>
        /// <param name="publishableNodeId"></param>
        /// <param name="jsonData"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool PublishDraftNode(int publishableNodeId, string name, string urlSlug, string uniqueAlias, string template, string jsonData, string currentUsername, ref string errorMsg)
        {
            try
            {
                // get node
                var publishable = this._dc.PublishableNodes
                    //.Include("DraftNode")
                    .SingleOrDefault(x => x.PublishableNodeId == publishableNodeId);

                // check
                if (publishable == null)
                {
                    errorMsg = "Publishable node #" + publishableNodeId + " does not exist.";
                    return false;
                }

                // get draft
                var draft = publishable.DraftNode;

                // check
                if (draft == null)
                {
                    errorMsg = "Publishable node #" + publishableNodeId + " has no draft node. Data may have changed since you began editing.";
                    return false;
                }

                // get now
                var now = DateTime.Now;

                // get parent
                var parent = publishable.ParentNode;

                // set
                publishable.SavedContentModelData = jsonData;
                publishable.LastUpdated = now;
                publishable.LastUpdatedUsername = currentUsername;
                publishable.FirstPublished = publishable.FirstPublished == null ? now : publishable.FirstPublished;
                publishable.DraftNode = null;
                publishable.UrlPortion = urlSlug.TrimEnd('-');
                publishable.Name = name;
                publishable.UniqueAlias = uniqueAlias;
                publishable.LastPublished = now;
                publishable.LastPublishedUsername = currentUsername;
                publishable.Template = template;

                if (!this.NameIsOk(publishable, NodeType.Publishable, ref errorMsg)) { return false; }
                if (!this.UrlIsOk(publishable, NodeType.Publishable, ref errorMsg)) { return false; }
                if (!this.UniqueAliasIsUnique(publishable, NodeType.Publishable, ref errorMsg)) { return false; }


                // remove draft
                this._dc.DraftNodes.Remove(draft);

                // save
                this._dc.SaveChanges();

                // ok!!
                return true;
            }
            catch (Exception ex)
            {
                errorMsg = "An error has occured: " + ex.Message;
                return false;
            }
        }

        /// <summary>
        /// Disposes data context
        /// </summary>
        public void DisposeDataContext()
        {
            this._dc.Dispose();
        }

        /// <summary>
        /// Revert to published node
        /// </summary>
        /// <param name="nodeId"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool RevertToPublished(int nodeId, string errorMsg)
        {
            try
            {
                // get node
                var publishable = this
                    ._dc.PublishableNodes
                    .AsEnumerable()
                    .Where(x => x.IsPublished)
                    .SingleOrDefault(x => x.PublishableNodeId == nodeId);

                // check
                if (publishable == null || publishable.DraftNode == null)
                {
                    errorMsg = "Publishable node #" + nodeId + " does not exist, is not yet published, or has no draft version.";
                }

                // get draft
                var draft = publishable.DraftNode;

                // remove
                publishable.DraftNode = null;
                this._dc.DraftNodes.Remove(draft);

                // save
                this._dc.SaveChanges();

                //
                return true;
            }
            catch (Exception ex)
            {
                errorMsg = "An error has occured: " + ex.Message;
                return false;
            }
        }

        /// <summary>
        /// Trash node/s
        /// </summary>
        /// <param name="nodeId"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool Trash(int nodeId, string currentUsername, ref string errorMsg)
        {
            try
            {
                // get node
                var node = this._dc.PublishableNodes.Find(nodeId);

                if (node == null)
                {
                    errorMsg = "Node #" + nodeId + " does not exist";
                    return false;
                }

                // find sibling
                if (node.HasParent)
                {
                    var siblingsAfter =
                        this._dc.PublishableNodes.Where(x =>
                            x.ParentNode.PublishableNodeId == node.ParentNode.PublishableNodeId &&
                            x.OrderInParent > node.OrderInParent);

                    // iterate and change order
                    foreach (var sib in siblingsAfter)
                    {
                        sib.OrderInParent--;
                        //this._dc.SaveChanges();
                    }
                }

                // start collection
                var collection = new List<PublishableNode>();

                // add to collection
                this.addNodeToTrashCollection(node, ref collection);

                // iterate collection and create trash
                foreach (var n in collection)
                {
                    // final
                    TrashedNode trashed = null;
                    NodeBase nodeToUse = null;

                    // check draft
                    if (n.HasDraft)
                    {
                        nodeToUse = n.DraftNode;
                    }
                    else
                    {
                        nodeToUse = n;
                    }

                    // get now
                    var now = DateTime.Now;

                    // create draft
                    trashed = new TrashedNode
                    {
                        ContentModelNameSpace = nodeToUse.ContentModelNameSpace,
                        ControllerNameSpace = nodeToUse.ControllerNameSpace,
                        FirstCreated = now,
                        FirstCreatedUsername = currentUsername,
                        LastUpdated = now,
                        LastUpdatedUsername = currentUsername,
                        Name = nodeToUse.Name,
                        TypeAlias = nodeToUse.TypeAlias,
                        SavedContentModelData = nodeToUse.SavedContentModelData,
                        Template = nodeToUse.Template,
                        TypeAssemblyName = nodeToUse.TypeAssemblyName,
                        UrlPortion = nodeToUse.UrlPortion,
                        UniqueAlias = nodeToUse.UniqueAlias
                    };

                    // save trashed
                    this._dc.TrashedNodes.Add(trashed);
                    this._dc.SaveChanges();

                    // delete draft
                    if (n.HasDraft)
                    {
                        this._dc.DraftNodes.Remove(n.DraftNode);
                    }

                    // delete node
                    this._dc.PublishableNodes.Remove(n);
                    this._dc.SaveChanges();
                }

                // 
                return true;
            }
            catch (Exception ex)
            {
                errorMsg = "An error has occured: " + ex.Message;
                return false;
            }
        }

        // recursion for trash method
        private void addNodeToTrashCollection(PublishableNode node, ref List<PublishableNode> collection)
        {
            // get children
            var childs = node.ChildNodes.ToList();

            // set childs
            childs.ForEach(n => n.ParentNode = null);

            // add to collection
            node.ChildNodes = null;

            // add
            collection.Add(node);

            // loop
            foreach (var child in childs)
            {
                addNodeToTrashCollection(child, ref collection);
            }
        }

        /// <summary>
        /// Trashed nodes
        /// </summary>
        public IQueryable<TrashedNode> TrashedNodes
        {
            get
            {
                return this._dc.TrashedNodes.AsQueryable();
            }
        }

        /// <summary>
        /// Delete trashed content
        /// </summary>
        /// <param name="trashedNodeId"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool DeleteTrashedContent(int trashedNodeId, ref string errorMsg)
        {
            try
            {
                // find
                var trashed = this._dc.TrashedNodes.Find(trashedNodeId);

                // delete
                this._dc.TrashedNodes.Remove(trashed);

                // save
                this._dc.SaveChanges();

                // ok
                return true;
            }
            catch (Exception ex)
            {
                errorMsg = ex.Message;
                return false;
            }
        }

        /// <summary>
        /// Returns parent id for child
        /// </summary>
        /// <param name="childId"></param>
        /// <returns></returns>
        public int? GetPublishableNodeParentId(int childId)
        {
            // get child
            var child = this._dc.PublishableNodes.Find(childId);

            // check
            if (child != null && child.ParentNode != null)
            {
                return child.ParentNode.PublishableNodeId;
            }

            // 
            return null;
        }

        /// <summary>
        /// Re order children of parent
        /// </summary>
        /// <param name="parentId"></param>
        /// <param name="orderedChildIds"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool ReOrderChildren(int parentId, int[] orderedChildIds, ref string error)
        {
            try
            {
                // get parent
                var parent = this.GetPublishableNodeFromNodeId(parentId);

                // loop
                for (int i = 0; i < orderedChildIds.Length; i++)
                {
                    // get child
                    var child = parent.ChildNodes.Single(x => x.PublishableNodeId == orderedChildIds[i]);

                    // set child
                    child.OrderInParent = i;
                }

                // save
                this._dc.SaveChanges();

                //
                return true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
                return false;
            }
        }

        /// <summary>
        /// Move nodes
        /// </summary>
        /// <param name="nodeToMoveId"></param>
        /// <param name="movingToNodeId"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public bool Move(int nodeToMoveId, int movingToNodeId, ref string errorMsg)
        {
            // get moving and movedto nodes
            var movingNode = this._dc.PublishableNodes.Find(nodeToMoveId);
            var newParentNode = this._dc.PublishableNodes.Find(movingToNodeId);

            // do null checks
            if (movingNode == null || newParentNode == null)
            {
                errorMsg = "Nodes do not exist";
                return false;
            }

            // do home check
            if (movingNode.IsRoot)
            {
                errorMsg = "Cannot move root content";
                return false;
            }

            // check for same parent
            if (newParentNode.PublishableNodeId == movingNode.ParentNode.PublishableNodeId)
            {
                errorMsg = "Node is already in this parent node";
                return false;
            }



            /** do parent checks **/

            // start
            var currentToCheck = newParentNode;

            // loop
            while (currentToCheck.PublishableNodeId != movingNode.PublishableNodeId && currentToCheck.HasParent)
            {
                currentToCheck = currentToCheck.ParentNode;
            }

            // check if has parent - if it does, throw error is it's not go to root node
            if (currentToCheck.HasParent)
            {
                errorMsg = "You cannot move content into itself or a branch of itself";
                return false;
            }

            // try to: 
            //          re-order original siblings where order > original
            //          change parent, order in parent and level in tree for moving node
            //          save changes
            try
            {
                // re-order originals
                movingNode
                    .ParentNode
                    .ChildNodes.Where(x =>
                        x.PublishableNodeId != movingNode.PublishableNodeId &&
                        x.OrderInParent > movingNode.OrderInParent)
                    .ToList()
                    .ForEach(n => n.OrderInParent--);

                // set order
                movingNode.OrderInParent = newParentNode.ChildNodes.Count;

                // change parent node
                movingNode.ParentNode = newParentNode;
                movingNode.LevelInTree = newParentNode.LevelInTree + 1;

                // do checks
                if (!this.NameIsOk(movingNode, NodeType.Publishable, ref errorMsg)) { return false; }
                if (!this.UrlIsOk(movingNode, NodeType.Publishable, ref errorMsg)) { return false; }
                if (!this.UniqueAliasIsUnique(movingNode, NodeType.Publishable, ref errorMsg)) { return false; }

                // save
                this._dc.SaveChanges();

                // ok
                return true;
            }

            // catch (set error return false)
            catch (Exception ex)
            {
                errorMsg = ex.Message;
                return false;
            }
        }

        /// <summary>
        /// Restore
        /// </summary>
        /// <param name="model"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool Restore(TrashedNode model, PublishableNode newPublishableNodeFromTrashed, ref string error, ref int newId)
        {
            try
            {
                // get root
                var root = this.GetRootNode();

                // check root
                if (root == null)
                {
                    error = "Cannot restore content when no root node exists!";
                    return false;
                }

                // set parent
                newPublishableNodeFromTrashed.ParentNode = root;

                // create new node
                if (this.CreateNewNode(newPublishableNodeFromTrashed, root == null ? null : (int?)root.PublishableNodeId, ref error, ref newId))
                {
                    // 
                    var newId_ = newId;

                    // get new publishable
                    var publishable = this._dc.PublishableNodes.Single(x => x.PublishableNodeId == newId_);

                    // create draft
                    var draft = publishable.DraftNode;// this.CreateAndGetDraftForPublished(publishable);

                    // save publishable
                    this.SaveDraftNode(publishable.PublishableNodeId, publishable.Name, publishable.UrlPortion, publishable.UniqueAlias, publishable.Template, publishable.SavedContentModelData, publishable.LastUpdatedUsername, ref error);

                    // delete trashed
                    var trashed = this._dc.TrashedNodes.Single(x => x.TrashedNodeId == model.TrashedNodeId);
                    this._dc.TrashedNodes.Remove(trashed);
                    this._dc.SaveChanges();

                    //
                    return true;
                }
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }

            // fallback
            return false;

        }

        /// <summary>
        /// Check name is ok
        /// </summary>
        /// <param name="node"></param>
        /// <param name="checkType"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool NameIsOk(NodeBase node, NodeType checkType, ref string error)
        {
            // set values
            this.setCheckingValues(node);

            // do draft checks
            if (checkType == NodeType.Both || checkType == NodeType.Draft)
            {
                if (_draftSiblings.Select(x => x.Name.ToLower()).Contains(_draft.Name.ToLower()))
                {
                    error = "Name '" + _draft.UrlPortion + "' is already in this content's siblings draft content. Please use another name.";
                    return false;
                }
            }

            // do published checks
            if (checkType == NodeType.Both || checkType == NodeType.Publishable)
            {
                if (_publishedSiblings.Select(x => x.Name.ToLower()).Contains(_publishable.Name.ToLower()))
                {
                    error = "Name '" + _publishable.Name + "' is already in this content's siblings publishable content. Please use another name.";
                    return false;
                }
            }

            return true;


        }

        /// <summary>
        /// Check url is ok
        /// </summary>
        /// <param name="node"></param>
        /// <param name="checkType"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool UrlIsOk(NodeBase node, NodeType checkType, ref string error)
        {
            // set values
            this.setCheckingValues(node);

            // do draft checks
            if (checkType == NodeType.Both || checkType == NodeType.Draft)
            {
                if (_draftSiblings.Select(x => x.UrlPortion.ToLower()).Contains(_draft.UrlPortion.ToLower()))
                {
                    error = "Url '" + _draft.UrlPortion + "' is already in this content's siblings draft content. Please use another url.";
                    return false;
                }
            }

            // do published checks
            if (checkType == NodeType.Both || checkType == NodeType.Publishable)
            {
                if (_publishedSiblings.Select(x => x.UrlPortion.ToLower()).Contains(_publishable.UrlPortion.ToLower()))
                {
                    error = "Url '" + _publishable.UrlPortion + "' is already in this content's siblings publishable content. Please use another url.";
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Check unique alias is unique
        /// </summary>
        /// <param name="node"></param>
        /// <param name="checkType"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool UniqueAliasIsUnique(NodeBase node, NodeType checkType, ref string error)
        {
            // set values
            this.setCheckingValues(node);

            // do draft checks
            if (checkType == NodeType.Both || checkType == NodeType.Draft)
            {
                // get aliases to check against
                var aliases = this._dc.DraftNodes.Where(x => x.DraftNodeId != _draft.DraftNodeId && !string.IsNullOrEmpty(x.UniqueAlias)).Select(x => x.UniqueAlias.ToLower()).ToList();

                if (_draft.UniqueAlias != null && aliases.Contains(_draft.UniqueAlias.ToLower()))
                {
                    error = "Unique alias '" + _draft.UniqueAlias + "' is already in use for this site's draft content. Please use another unique alias.";
                    return false;
                }
            }

            // do published checks
            if (checkType == NodeType.Both || checkType == NodeType.Publishable)
            {
                // get aliases to check against
                var aliases = this._dc.PublishableNodes.AsEnumerable().Where(x => x.IsPublished && x.PublishableNodeId != _publishable.PublishableNodeId && !string.IsNullOrEmpty(x.UniqueAlias)).Select(x => x.UniqueAlias.ToLower()).ToList();

                if (_publishable.UniqueAlias != null && aliases.Contains(_publishable.UniqueAlias.ToLower()))
                {
                    error = "Unique alias '" + _publishable.UniqueAlias + "' is already in use for this site's publishable content. Please use another unique alias.";
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Get siblings of node
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public IQueryable<PublishableNode> GetSiblingsForNode(PublishableNode node)
        {
            if (node.HasParent)
            {
                return node.ParentNode.ChildNodes.Where(x => x.PublishableNodeId != node.PublishableNodeId).AsQueryable();
            }

            return new List<PublishableNode>(0).AsQueryable();
        }

        /// <summary>
        /// Returns publishable nodes
        /// </summary>
        /// <param name="publishedOnly"></param>
        /// <returns></returns>
        public IQueryable<PublishableNode> GetPublishableNodes(bool publishedOnly)
        {
            if (publishedOnly)
            {
                return this._dc.PublishableNodes.AsEnumerable().Where(x => x.IsPublished).AsQueryable();
            }
            return this._dc.PublishableNodes;
        }

        /// <summary>
        /// Sets checking values
        /// </summary>
        /// <param name="node"></param>
        private void setCheckingValues(NodeBase node)
        {
            // get type
            var typeOfNodeBase = node.GetType();
            var publishableType = typeof(PublishableNode);
            var draftType = typeof(DraftNode);

            // set
            if (typeOfNodeBase == publishableType || typeOfNodeBase.BaseType == publishableType)
            {
                _publishable = (PublishableNode)node;
                _parent = _publishable.ParentNode;
                _draft = _publishable.HasDraft ? _publishable.DraftNode : new DraftNode { Name = _publishable.Name, UrlPortion = _publishable.UrlPortion, UniqueAlias = _publishable.UniqueAlias };
            }
            if (typeOfNodeBase == draftType || typeOfNodeBase.BaseType == draftType)
            {
                _draft = (DraftNode)node;
                _publishable = this._dc.PublishableNodes.Single(x => x.DraftNode.DraftNodeId == _draft.DraftNodeId);
                _parent = _publishable.ParentNode;
            }

            // set
            _publishedSiblings =
                this.GetSiblingsForNode(_publishable).ToList();
            _draftSiblings = _publishedSiblings.Where(x => x.HasDraft).Select(x => x.DraftNode).ToList();
            _publishedSiblings = _publishedSiblings.Where(x => x.IsPublished).ToList();
        }



        // checking values
        PublishableNode _publishable = null;
        DraftNode _draft = null;
        PublishableNode _parent = null;
        List<PublishableNode> _publishedSiblings = null;
        List<DraftNode> _draftSiblings = null;
    }
}
